// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: junglekim
#pragma once

#include <algorithm>
#include <memory>
#include <limits>
#include <iomanip>

#include <gflags/gflags.h>

#include "coin2/exchange/base/symbology/product_info.h"
#include "coin2/exchange/factory/symbology/product.h"
#include "coin2/exchange/base/symbology/product_encyclopedia.h"
#include "coin2/strategy/order_executor.pb.h"
#include "coin2/strategy/order_executor/mm_executor.h"
#include "coin2/strategy/order_executor/executor.h"
#include "coin2/strategy/order_executor/layering_executor2.h"
#include "coin2/strategy/strategy.h"

using coin2::app::Driver;
using coin2::exchange::base::feed::FeedUpdate;
using coin2::exchange::base::feed::FeedTimer;
using coin2::exchange::base::order::IOrderSubsystem;
using coin2::exchange::base::order::OrderUpdate;
using coin2::strategy::PassiveExecutorConfig;
using IProductHolder = coin2::exchange::base::symbology::IProductHolder;
using coin2::exchange::base::symbology::IProduct;
using coin2::exchange::base::symbology::IProductInfo;
using coin2::exchange::base::symbology::ProductEncyclopedia;
using coin2::strategy::order_executor::PassiveOrderExecutor;
using coin2::strategy::order_executor::LayeringExecutor2;
using coin::proto::OrderSide;
using coin::proto::OrderEvent;

namespace coin2::appcoin2::support::mm_helper {

class MMEducatorStrategy : public coin2::strategy::IStrategy {
 public:
  MMEducatorStrategy(
      double max_loss_quote,
      double lot_size,
      double order_update_period,
      std::string start_datetime,
      double buy_price,
      double sell_price)
      : max_loss_quote_(max_loss_quote),
        lot_size_(lot_size),
        order_update_period_(order_update_period * 1e9),
        start_datetime_(start_datetime),
        buy_price_(buy_price),
        sell_price_(sell_price) {
    CHECK(lot_size_ > 0) << "lot_size must be greater than zero";
    CHECK(!(buy_price_ && sell_price_)) << "You cannot buy and sell at once";
  }

  void Init(Driver* driver) override;
  void onCleanup(Driver* driver) override;

  void onBookFeed(const FeedUpdate& upd) override;
  // void onTradeFeed(const FeedUpdate& upd) override;
  // void onHeartbeatFeed(const FeedTimer& timer) override;
  void onAccountOrder(const OrderUpdate& upd) override;
  void onAccountInfo(const OrderUpdate& upd) override;
  // void onOrderLog(const OrderGatewayLog& log) override;

  void Report();
  int64_t Readable2Epoch(std::string readable);
  std::string GetSymbol(const IProduct& product);
  double RoundUp(double value, int decimal);

 private:
  IOrderSubsystem* os();
  const IProductInfo* pi_{nullptr};

  Driver* driver_{nullptr};
  std::unique_ptr<LayeringExecutor2> executor_;
  const IProductHolder* product_holder_;
  PassiveExecutorConfig exe_config_;

  double max_loss_quote_;
  double lot_size_;
  int64_t order_update_period_;
  std::string start_datetime_;
  int64_t timestamp0_{0};

  double buy_price_{0};
  double sell_price_{0};

  std::unordered_map<double, double> fills_;
  double midp_{0};
  int64_t last_report_ts_{0};
  std::string symbol_;
  std::string owner_;
  bool done_{false};
};
}  // namespace coin2::appcoin2::support::mm_helper